#pragma once

#include "LoadField.inl"

namespace common {

class Base {
public:
    void load(const std::string &filename, const std::string &child);

    virtual Base *loadField(uint64_t field, const std::string &value) { return nullptr; }
    virtual bool loaded() { return true; }
};

class UniqueBase: public Base {
public:
    Base *loadField(uint64_t field, const std::string &value) override;

    inline int32_t uid() const { return uid_; }
    inline const std::string &name() const { return name_; }

protected:
    // unique id
    int32_t uid_ = 0;
    // data name
    std::string name_;
};

class BaseMgrLoader {
protected:
    BaseMgrLoader() {}

public:
    virtual ~BaseMgrLoader() {}

    void load(const std::string &filename);

protected:
    virtual void loaded() {}

    virtual Base *newBase() = 0;
    virtual void addBase(Base*) = 0;
};

template<typename T>
class IDBaseMgr: public BaseMgrLoader {
public:
    typedef T BaseType;

    virtual void add(std::shared_ptr<BaseType> data) {
        objs_[data->uid()] = data;
    }

    virtual void remove(int32_t uid) {
        objs_.erase(uid);
    }

    inline std::shared_ptr<BaseType> get(int32_t uid) {
        auto ite = objs_.find(uid);
        if (ite == objs_.end()) return nullptr;
        return ite->second;
    }

    inline std::map<int32_t, std::shared_ptr<BaseType>> &GetObjects() { return objs_; }

private:
    Base *newBase() override {
        return new T;
    }

    void addBase(Base *obj) override {
        add(std::shared_ptr<T>(static_cast<T*>(obj)));
    }

protected:
    std::map<int32_t, std::shared_ptr<BaseType>> objs_;
};

template<typename T>
class NameBaseMgr : public BaseMgrLoader {
public:
    typedef T BaseType;

    virtual void add(std::shared_ptr<BaseType> data) {
        objs_[data->name()] = data;
    }

    inline std::shared_ptr<BaseType> get(const std::string &name) {
        auto ite = objs_.find(name);
        if (ite == objs_.end()) return nullptr;
        return ite->second;
    }

private:
    Base *newBase() override {
        return new T;
    }

    void addBase(Base *obj) override {
        objs_[static_cast<T*>(obj)->name()] = std::shared_ptr<T>(static_cast<T*>(obj));
    }

protected:
    std::map<std::string, std::shared_ptr<BaseType>> objs_;
};

}
